/****************************************************************
 * Fulguro
 * Copyright (C) 2004 Christophe Clienti
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 ***************************************************************/


#include <string.h>
#include <flgrCoreDispatch.h>
#include <flgrCoreData.h>
#include <flgrCoreDataIO.h>
#include <flgrCoreShift.h>
#include <flgrCoreShiftFast.h>


/*!
 * \defgroup group_fulguro_core_shift Shift functions
 * \ingroup group_fulguro_core
 * @{
 */


/////////////////////////////////////////////////////////////
// macro for different type of flgr1d_shift_right
/////////////////////////////////////////////////////////////
#define FLGR_MACRO_SHIFT1D_RIGHT(dtype)			\
  dtype *psrc = (dtype *) datsrc->array;		\
  dtype *pdest = (dtype *) datdest->array;		\
  dtype *pinsert = (dtype*) vec_insert->array;		\
  int l = datsrc->length;				\
  int m = l-nbshift;					\
  int i,spp = datsrc->spp;				\
  dtype val;						\
							\
  FLGR_DECLARE_FUNCTION;				\
							\
  if(nbshift >= datsrc->length) return;			\
							\
  for(i=0 ; i<nbshift*spp ; i++) {			\
    val = flgr_get_array_##dtype(pinsert,i%spp);	\
    flgr1d_set_data_array_##dtype(pdest,i,val);		\
  }							\
							\
  memcpy(pdest+nbshift*spp,psrc,m*spp*sizeof(dtype));	\
  return

void flgr1d_shift_right_fgBIT(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int nbshift, FLGR_Vector *vec_insert) {
  fgBIT *psrc = (fgBIT *) datsrc->array;
  fgBIT *pdest = (fgBIT *) datdest->array;
  fgBIT *pinsert = vec_insert->array;
  fgBIT val;
  int l = sizeof(fgBIT)<<3;
  int k,m;
  int j,spp = datsrc->spp;

  FLGR_DECLARE_FUNCTION;

  if(nbshift >= datsrc->length) return;
  
  if((nbshift==1) && (datsrc->spp == 1))
    return flgr1d_shift_1_right_spp1_fgBIT(datdest, datsrc, *((fgBIT *) (vec_insert->array)));

  l = datsrc->length;
  m = l-nbshift;

  for(j=0 ; j<nbshift*spp ; j++) {
    val = flgr_get_array_fgBIT(pinsert,j%spp);
    flgr1d_set_data_array_fgBIT(pdest,j,val);
  }

  for(j=0,k=nbshift*spp ; j<m*spp ; k++,j++) {
    val = flgr1d_get_data_array_fgBIT(psrc,j);
    flgr1d_set_data_array_fgBIT(pdest,k,val);
  }

}
void flgr1d_shift_right_fgUINT8(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int nbshift, FLGR_Vector *vec_insert) {
  FLGR_MACRO_SHIFT1D_RIGHT(fgUINT8);
}
void flgr1d_shift_right_fgUINT16(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int nbshift, FLGR_Vector *vec_insert) {
  FLGR_MACRO_SHIFT1D_RIGHT(fgUINT16);
}
void flgr1d_shift_right_fgUINT32(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int nbshift, FLGR_Vector *vec_insert) {
  FLGR_MACRO_SHIFT1D_RIGHT(fgUINT32);
}
void flgr1d_shift_right_fgINT8(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int nbshift, FLGR_Vector *vec_insert) {
  FLGR_MACRO_SHIFT1D_RIGHT(fgINT8);
}
void flgr1d_shift_right_fgINT16(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int nbshift, FLGR_Vector *vec_insert) {
  FLGR_MACRO_SHIFT1D_RIGHT(fgINT16);
}
void flgr1d_shift_right_fgINT32(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int nbshift, FLGR_Vector *vec_insert) {
  FLGR_MACRO_SHIFT1D_RIGHT(fgINT32);
}
void flgr1d_shift_right_fgFLOAT32(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int nbshift, FLGR_Vector *vec_insert) {
  FLGR_MACRO_SHIFT1D_RIGHT(fgFLOAT32);
}
void flgr1d_shift_right_fgFLOAT64(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int nbshift, FLGR_Vector *vec_insert) {
  FLGR_MACRO_SHIFT1D_RIGHT(fgFLOAT64);
}


////////////////////////////////////////////////////////////////////////////
/*! Right Shift1d 1D data
 *  @param datdest : pointer to FLGR_Data1D
 *  @param datsrc : pointer to FLGR_Data1D
 *  @param nbshift : how many pixels vectors to insert on the left
 *  @param vec_insert : pointer to a vector
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr1d_shift_right(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int nbshift, FLGR_Vector *vec_insert) {
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;

  if((datdest==NULL) || (datsrc==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if((ret = flgr1d_is_data_same_attributes(datdest,datsrc,__FUNCTION__)) != FLGR_RET_OK) return ret;

  if(nbshift >= datsrc->length) return FLGR_RET_PARAM_ERROR;

  FLGR_DISPATCH_PROCEDURE(datdest->type,flgr1d_shift_right,datdest,datsrc,nbshift,vec_insert);
}




/////////////////////////////////////////////////////////////
// macro for different type of flgr1d_shift_leftt
/////////////////////////////////////////////////////////////
#define FLGR_MACRO_SHIFT1D_LEFT(dtype)			\
  dtype *psrc = (dtype *) datsrc->array;		\
  dtype *pdest = (dtype *) datdest->array;		\
  dtype *pinsert = vec_insert->array;			\
  int l = datsrc->length;				\
  int m = l-nbshift;					\
  int i,spp = datsrc->spp;				\
  dtype val;						\
							\
  FLGR_DECLARE_FUNCTION;				\
							\
							\
  if(nbshift >= datsrc->length) return;			\
							\
  for(i=(l-nbshift)*spp ; i<l*spp ; i++) {		\
    val = flgr_get_array_##dtype(pinsert,i%spp);	\
    flgr1d_set_data_array_##dtype(pdest,i,val);		\
  }							\
							\
  memcpy(pdest,psrc+nbshift*spp,m*spp*sizeof(dtype));	\
  return


void flgr1d_shift_left_fgBIT(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int nbshift, FLGR_Vector *vec_insert) {
  fgBIT *psrc = (fgBIT *) datsrc->array;
  fgBIT *pdest = (fgBIT *) datdest->array;
  fgBIT *pinsert = (fgBIT*) vec_insert->array;
  fgBIT val;
  int l = datsrc->length;
  int m = l-nbshift;
  int j,k,spp = datsrc->spp;

  if((nbshift==1) && (datsrc->spp == 1))
    return flgr1d_shift_1_left_spp1_fgBIT(datdest, datsrc, *((fgBIT *) (vec_insert->array)));
  
  if(nbshift >= datsrc->length) return;
  
  for(j=m*spp ; j<l*spp ; j++){
    val = flgr_get_array_fgBIT(pinsert,j%spp);
    flgr1d_set_data_array_fgBIT(pdest,j,val);
  }

  for(j=0,k=nbshift*spp ; j<m*spp ; k++,j++) {
    val = flgr1d_get_data_array_fgBIT(psrc,k);
    flgr1d_set_data_array_fgBIT(pdest,j,val);
  }
}
void flgr1d_shift_left_fgUINT8(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int nbshift, FLGR_Vector *vec_insert) {
  FLGR_MACRO_SHIFT1D_LEFT(fgUINT8);
}
void flgr1d_shift_left_fgUINT16(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int nbshift, FLGR_Vector *vec_insert) {
  FLGR_MACRO_SHIFT1D_LEFT(fgUINT16);
}
void flgr1d_shift_left_fgUINT32(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int nbshift, FLGR_Vector *vec_insert) {
  FLGR_MACRO_SHIFT1D_LEFT(fgUINT32);
}
void flgr1d_shift_left_fgINT8(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int nbshift, FLGR_Vector *vec_insert) {
  FLGR_MACRO_SHIFT1D_LEFT(fgINT8);
}
void flgr1d_shift_left_fgINT16(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int nbshift, FLGR_Vector *vec_insert) {
  FLGR_MACRO_SHIFT1D_LEFT(fgINT16);
}
void flgr1d_shift_left_fgINT32(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int nbshift, FLGR_Vector *vec_insert) {
  FLGR_MACRO_SHIFT1D_LEFT(fgINT32);
}
void flgr1d_shift_left_fgFLOAT32(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int nbshift, FLGR_Vector *vec_insert) {
  FLGR_MACRO_SHIFT1D_LEFT(fgFLOAT32);
}
void flgr1d_shift_left_fgFLOAT64(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int nbshift, FLGR_Vector *vec_insert) {
  FLGR_MACRO_SHIFT1D_LEFT(fgFLOAT64);
}


////////////////////////////////////////////////////////////////////////////
/*! Left Shift 1D data
 *  @param datdest : pointer to FLGR_Data1D
 *  @param datsrc : pointer to FLGR_Data1D
 *  @param nbshift : how many pixels vectors to insert on the right
 *  @param vec_insert : pointer to a vector
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr1d_shift_left(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int nbshift, FLGR_Vector *vec_insert) {
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;

  if((datdest==NULL) || (datsrc==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if((ret = flgr1d_is_data_same_attributes(datdest,datsrc,__FUNCTION__)) != FLGR_RET_OK) return ret;

  if(nbshift >= datsrc->length) return FLGR_RET_PARAM_ERROR;

  FLGR_DISPATCH_PROCEDURE(datdest->type,flgr1d_shift_left,datdest,datsrc,nbshift,vec_insert);
}
















/////////////////////////////////////////////////////////////
// macro for different type of flgr1d_shift_circular_right
/////////////////////////////////////////////////////////////
#define FLGR_MACRO_SHIFT1D_CIRCULAR_RIGHT(dtype)	\
  dtype *psrc = (dtype *) datsrc->array;		\
  dtype *pdest = (dtype *) datdest->array;		\
  int l = datsrc->length;				\
  int m = l-nbshift;					\
  int spp = datsrc->spp;				\
							\
  FLGR_DECLARE_FUNCTION;				\
							\
  if(nbshift >= datsrc->length) return;			\
							\
							\
  memcpy(pdest,psrc+m*spp,nbshift*spp*sizeof(dtype));	\
  memcpy(pdest+nbshift*spp,psrc,m*spp*sizeof(dtype))

//fgBIT is not optimized for the moment ...
void flgr1d_shift_circular_right_fgBIT(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int nbshift) {
  fgBIT *psrc = (fgBIT *) datsrc->array;
  fgBIT *pdest = (fgBIT *) datdest->array;
  fgBIT val;
  int l = sizeof(fgBIT)<<3;
  int k,m;
  int j,spp = datsrc->spp;

  
  if(nbshift >= datsrc->length) return;
  
  l = datsrc->length;
  m = l-nbshift;

  for(j=0,k=m*spp ; j<nbshift*spp ; j++,k++) {
    val = flgr1d_get_data_array_fgBIT(psrc,k);
    flgr1d_set_data_array_fgBIT(pdest,j,val);
  }

  for(j=0,k=nbshift*spp ; j<m*spp ; k++,j++) {
    val = flgr1d_get_data_array_fgBIT(psrc,j);
    flgr1d_set_data_array_fgBIT(pdest,k,val);
  }

}
void flgr1d_shift_circular_right_fgUINT8(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int nbshift) {
  FLGR_MACRO_SHIFT1D_CIRCULAR_RIGHT(fgUINT8);
}
void flgr1d_shift_circular_right_fgUINT16(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int nbshift) {
  FLGR_MACRO_SHIFT1D_CIRCULAR_RIGHT(fgUINT16);
}
void flgr1d_shift_circular_right_fgUINT32(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int nbshift) {
  FLGR_MACRO_SHIFT1D_CIRCULAR_RIGHT(fgUINT32);
}
void flgr1d_shift_circular_right_fgINT8(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int nbshift) {
  FLGR_MACRO_SHIFT1D_CIRCULAR_RIGHT(fgINT8);
}
void flgr1d_shift_circular_right_fgINT16(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int nbshift) {
  FLGR_MACRO_SHIFT1D_CIRCULAR_RIGHT(fgINT16);
}
void flgr1d_shift_circular_right_fgINT32(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int nbshift) {
  FLGR_MACRO_SHIFT1D_CIRCULAR_RIGHT(fgINT32);
}
void flgr1d_shift_circular_right_fgFLOAT32(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int nbshift) {
  FLGR_MACRO_SHIFT1D_CIRCULAR_RIGHT(fgFLOAT32);
}
void flgr1d_shift_circular_right_fgFLOAT64(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int nbshift) {
  FLGR_MACRO_SHIFT1D_CIRCULAR_RIGHT(fgFLOAT64);
}
////////////////////////////////////////////////////////////////////////////
/*! Circular Right Shift 1D data
 *  @param datdest : pointer to FLGR_Data1D
 *  @param datsrc : pointer to FLGR_Data1D
 *  @param nbshift : how many pixels vectors to insert on the left
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr1d_shift_circular_right(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int nbshift) {
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;

  if((datdest==NULL) || (datsrc==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if((ret = flgr1d_is_data_same_attributes(datdest,datsrc,__FUNCTION__)) != FLGR_RET_OK) return ret;

  if(nbshift >= datsrc->length) return FLGR_RET_PARAM_ERROR;

  FLGR_DISPATCH_PROCEDURE(datdest->type,flgr1d_shift_circular_right,datdest,datsrc,nbshift);
}






/////////////////////////////////////////////////////////////
// macro for different type of flgr1d_shift_circular_left
/////////////////////////////////////////////////////////////
#define FLGR_MACRO_SHIFT1D_CIRCULAR_LEFT(dtype)		\
  dtype *psrc = (dtype *) datsrc->array;		\
  dtype *pdest = (dtype *) datdest->array;		\
  int l = datsrc->length;				\
  int m = l-nbshift;					\
  int spp = datsrc->spp;				\
							\
  FLGR_DECLARE_FUNCTION;				\
							\
  if(nbshift >= datsrc->length) return;			\
							\
  memcpy(pdest+m*spp,psrc,nbshift*spp*sizeof(dtype));	\
  memcpy(pdest,psrc+nbshift*spp,m*spp*sizeof(dtype))

//fgBIT is not optimized for the moment ...
void flgr1d_shift_circular_left_fgBIT(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int nbshift) {
  fgBIT *psrc = (fgBIT *) datsrc->array;
  fgBIT *pdest = (fgBIT *) datdest->array;
  fgBIT val;
  int l = sizeof(fgBIT)<<3;
  int k,m;
  int j,spp = datsrc->spp;

  
  if(nbshift >= datsrc->length) return;
  
  l = datsrc->length;
  m = l-nbshift;

  for(j=0,k=m*spp ; j<nbshift*spp ; j++,k++) {
    val = flgr1d_get_data_array_fgBIT(psrc,j);
    flgr1d_set_data_array_fgBIT(pdest,k,val);
  }

  for(j=0,k=nbshift*spp ; j<m*spp ; k++,j++) {
    val = flgr1d_get_data_array_fgBIT(psrc,k);
    flgr1d_set_data_array_fgBIT(pdest,j,val);
  }

}
void flgr1d_shift_circular_left_fgUINT8(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int nbshift) {
  FLGR_MACRO_SHIFT1D_CIRCULAR_LEFT(fgUINT8);
}
void flgr1d_shift_circular_left_fgUINT16(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int nbshift) {
  FLGR_MACRO_SHIFT1D_CIRCULAR_LEFT(fgUINT16);
}
void flgr1d_shift_circular_left_fgUINT32(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int nbshift) {
  FLGR_MACRO_SHIFT1D_CIRCULAR_LEFT(fgUINT32);
}
void flgr1d_shift_circular_left_fgINT8(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int nbshift) {
  FLGR_MACRO_SHIFT1D_CIRCULAR_LEFT(fgINT8);
}
void flgr1d_shift_circular_left_fgINT16(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int nbshift) {
  FLGR_MACRO_SHIFT1D_CIRCULAR_LEFT(fgINT16);
}
void flgr1d_shift_circular_left_fgINT32(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int nbshift) {
  FLGR_MACRO_SHIFT1D_CIRCULAR_LEFT(fgINT32);
}
void flgr1d_shift_circular_left_fgFLOAT32(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int nbshift) {
  FLGR_MACRO_SHIFT1D_CIRCULAR_LEFT(fgFLOAT32);
}
void flgr1d_shift_circular_left_fgFLOAT64(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int nbshift) {
  FLGR_MACRO_SHIFT1D_CIRCULAR_LEFT(fgFLOAT64);
}
////////////////////////////////////////////////////////////////////////////
/*! Circular Left Shift 1D data
 *  @param datdest : pointer to FLGR_Data1D
 *  @param datsrc : pointer to FLGR_Data1D
 *  @param nbshift : how many pixels vectors to insert on the left
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr1d_shift_circular_left(FLGR_Data1D *datdest, FLGR_Data1D *datsrc, int nbshift) {
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;

  if((datdest==NULL) || (datsrc==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }

  if((ret = flgr1d_is_data_same_attributes(datdest,datsrc,__FUNCTION__)) != FLGR_RET_OK) return ret;

  if(nbshift >= datsrc->length) return FLGR_RET_PARAM_ERROR;

  FLGR_DISPATCH_PROCEDURE(datdest->type,flgr1d_shift_circular_left,datdest,datsrc,nbshift);
}



//! @}
